/*
 * OrderBean.java
 *
 * Created on 27 March 2007, 12:41
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package usyd.comp5348;

import java.util.Date;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.naming.NamingException;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import usyd.comp5348.CustomerInfo;
import usyd.comp5348.CustomerException;
import usyd.comp5348.CustomerRemote;
import usyd.comp5348.CatalogueInfo;
import usyd.comp5348.CatalogueRemoteFactory;
import usyd.comp5348.CustomerRemoteFactory;
import usyd.comp5348.DeliveryRemoteFactory;
import usyd.comp5348.utils.SettingsProvider;

/**
 *
 * @author Yuezhong Zhang
 */
@Stateless(mappedName="ejb/Order")
public class OrderBean implements OrderRemote, OrderLocal {
    
    @PersistenceContext
    private EntityManager em;
    
    /** Creates a new instance of OrderBean */
    public OrderBean() {
    }
    
    public int createOrder(OrderInfo order) throws OrderException {
        try{
            this.validateOrder(order);
            float cost = this.calculateOrderCost(order);
            order.setTotal(cost);
            order.setOrderDate(new Date());
            order.setStore(SettingsProvider.getApplicationServerAddress());
            Order o = new Order(order);
            em.persist(o);
            // flush it so the ID is correct .... GRRR this one took a while to sort out!
            em.flush();
            order.setId(o.getId());
            return order.getId();
        } catch(Exception e) {
            e.printStackTrace();
            throw new OrderException("Could not create new order", e);
        }
    }
    
    protected void _modifyOrder(Order order) throws OrderException{
        try{
            em.merge(order);
        } catch(Exception e) {
            e.printStackTrace();
            throw new OrderException("Could not modify order", e);
        }
    }
    
    public void modifyOrder(OrderInfo order) throws OrderException{
        try{
            order.setStore(SettingsProvider.getApplicationServerAddress());
            Order o = new Order(order);
            List<OrderLine> lines = em.createNamedQuery("getOrderLineByOrderId").setParameter("order", o).getResultList();
            for (OrderLine line : lines) {
                em.remove(line);
            }
            em.flush();
            em.merge(o);
        } catch(Exception e) {
            e.printStackTrace();
            throw new OrderException("Could not modify order", e);
        }
    }
    
    public void deleteOrder(int id) throws OrderException{
        Order o;
        try {
            o = em.find(Order.class, id);
            if (o!=null)
                em.remove(o);
        } catch (Exception e) {
            e.printStackTrace();
            throw new OrderException("Could not delete order",e);
        }
        if (o==null)
            throw new OrderException("Could not delete order(" + id + ") - does not exist");
    }
    
    public void submitOrder(int id) throws OrderException {
        Order o = _getOrderById(id);
        if (o == null)
            throw new OrderException("Could not submit order(" + id + ") - does not exist");
        if (o.getStatus() != OrderInfo.PENDING) {
            throw new OrderException("Order already submitted");
        }
        assert(o.getStore().equals(SettingsProvider.getApplicationServerAddress()));
        DeliveryInfo del = new DeliveryInfo(id,o.getWarehouse(), new Date(), OrderInfo.SUBMITTED, o.getStore());
        try {
            DeliveryRemote deliveryBean = DeliveryRemoteFactory.getInstance().getDeliveryRemote(o.getWarehouse());
            int delId = deliveryBean.createDelivery(del);
            deliveryBean.submitDelivery(delId);
        } catch (DeliveryException ex) {
            ex.printStackTrace();
            throw new OrderException("Failed to submit delivery", ex);
        } catch (NamingException ex) {
            ex.printStackTrace();
            throw new OrderException("Could not access remote warehouse Delivery system", ex);
        }
    }
    
    protected Order _getOrderById(int id) {
        return em.find(Order.class,id);
    }
    
    public OrderInfo getOrderById(int id) {
        Order o = em.find(Order.class,id);
        if (o==null)
            return null;
        return o.getOrderInfo();
    }
    
    public void updateOrderStatus(int id, int newStatus) throws OrderException {
        Order o = _getOrderById(id);
        if (o!=null) {
            o.setStatus(newStatus);
        } else
            throw new OrderException("Could not update order(" + id + ") - does not exist");
        _modifyOrder(o);
    }
    
    public float calculateOrderCost(OrderInfo order) throws OrderException {
        try {
            float cost = 0.0f;
            CatalogueRemote catalogueBean = CatalogueRemoteFactory.getInstance().getCatalogueRemote();
            for(OrderLineInfo ol : order.getVideos()) {
                try {
                    CatalogueInfo cat = catalogueBean.getVideoById(ol.getCatalogue_id());
                    if (cat==null)
                        throw new OrderException("Catalogue not found");
                    cost += cat.getPrice();
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new OrderException("Could not get Catalogue", e);
                }
            }
            return cost;
        } catch (Exception e) {
            e.printStackTrace();
            throw new OrderException("Could not calculate total cost", e);
        }
    }
    
    public void validateOrder(OrderInfo order) throws OrderException {
        try {
            if (order.getStatus()!=OrderInfo.PENDING) {
                throw new OrderException("Order already submitted");
            }
            CustomerRemote customerBean = CustomerRemoteFactory.getInstance().getCustomerRemote();
            CustomerInfo cust = customerBean.getCustomerById(order.getCustomerId());
            if(cust == null)
                throw new OrderException("Customer not found");
            
            for(OrderLineInfo ol : order.getVideos()){
                int id = ol.getCatalogue_id();
                CatalogueRemote catalogueBean = CatalogueRemoteFactory.getInstance().getCatalogueRemote();
                CatalogueInfo c = catalogueBean.getVideoById(id);
                if(c == null) {
                    throw new OrderException("Video #" + id + " not found in catalogue");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new OrderException("Could not validate order", e);
        }
    }
    
}
